#include <cnix/string.h>
#include <cnix/errno.h>
#include <cnix/devices.h>
#include <cnix/fs.h>
#include <cnix/mm.h>
#include <cnix/kernel.h>

int do_stat(const char * pathname, struct stat * statbuf)
{
	int error;
	int ret;
	struct inode * inoptr;
	struct stat statbuf1;

	checkname(pathname);

	inoptr = namei(pathname, &error, 0);
	if(!inoptr)
		return error;

	ret = inoptr->i_ops->stat(inoptr, &statbuf1);
	if(ret < 0)
	{
		iput(inoptr);
		return ret;
	}

	if(memcpy_to_user(statbuf, &statbuf1, sizeof(struct stat)) < 0)
	{
		iput(inoptr);
		return -EFAULT;
	}

	iput(inoptr);

	return 0;
}

int do_lstat(const char * pathname, struct stat * statbuf)
{
	int error;
	int ret;
	struct inode * inoptr;
	struct stat statbuf1;

	checkname(pathname);

	inoptr = namei0(pathname, &error, 0);
	if(!inoptr)
		return error;

	ret = inoptr->i_ops->stat(inoptr, &statbuf1);
	if(ret < 0)
	{
		iput(inoptr);
		return ret;
	}

	if(memcpy_to_user(statbuf, &statbuf1, sizeof(struct stat)) < 0)
	{
		iput(inoptr);
		return -EFAULT;
	}

	iput(inoptr);

	return 0;
}

int __do_fstat(int fd, struct stat * statbuf, BOOLEAN kernel)
{
	int ret;
	struct filp * fp;
	struct inode * inoptr;
	struct stat statbuf1;

	fp = fget(fd);
	if(!fp)
		DIE("BUG: cannot happen\n");

	memset(&statbuf1, 0, sizeof(struct stat));

	inoptr = fp->f_ino;

	if (is_socket(inoptr))
	{
		statbuf1.st_mode = I_SOCK | 0777;
	}
	else if(is_pipe(inoptr))
	{
		statbuf1.st_mode = I_FIFO | 0777;
	}
	else
	{
		ret = inoptr->i_ops->stat(inoptr, &statbuf1);
		if(ret < 0)
			return ret;
	}

        if (kernel)
        {
                memcpy(statbuf, &statbuf1, sizeof(struct stat));
        }
        else
        {
        	if(memcpy_to_user(statbuf, &statbuf1, sizeof(struct stat)) < 0)
        	{
        		return -EFAULT;
        	}
        }

	return 0;
}


int do_fstat(int fd, struct stat * statbuf)
{
	return __do_fstat(fd, statbuf, FALSE);
}
